<template>
  <div class="validated-input">
    <label v-if="label" :for="inputId" class="block text-sm font-medium text-gray-700 mb-1">
      {{ label }}
      <span v-if="required" class="text-red-500 ml-1">*</span>
    </label>
    
    <div class="relative">
      <input
        :id="inputId"
        v-model="inputValue"
        :type="type"
        :placeholder="placeholder"
        :disabled="disabled"
        :readonly="readonly"
        :class="inputClass"
        @blur="handleBlur"
        @focus="handleFocus"
        @input="handleInput"
      />
      
      <div v-if="showIcon" class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
        <Icon
          v-if="hasError"
          name="XCircle"
          class="h-5 w-5 text-red-400"
        />
        <Icon
          v-else-if="isValid && touched"
          name="CheckCircle"
          class="h-5 w-5 text-green-400"
        />
      </div>
    </div>
    
    <div v-if="hasError || hint" class="mt-1 text-sm">
      <p v-if="hasError" class="text-red-600">{{ errorMessage }}</p>
      <p v-else-if="hint" class="text-gray-500">{{ hint }}</p>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch, nextTick } from 'vue'
import Icon from './Icon.vue'

interface Props {
  modelValue?: string | number
  label?: string
  type?: string
  placeholder?: string
  required?: boolean
  disabled?: boolean
  readonly?: boolean
  hint?: string
  rules?: Array<(value: any) => boolean | string>
  validateOnBlur?: boolean
  validateOnInput?: boolean
  showIcon?: boolean
  size?: 'small' | 'medium' | 'large'
}

interface Emits {
  (e: 'update:modelValue', value: string | number): void
  (e: 'blur', event: FocusEvent): void
  (e: 'focus', event: FocusEvent): void
  (e: 'input', event: Event): void
  (e: 'validate', isValid: boolean, errorMessage?: string): void
}

const props = withDefaults(defineProps<Props>(), {
  type: 'text',
  validateOnBlur: true,
  validateOnInput: false,
  showIcon: true,
  size: 'medium'
})

const emit = defineEmits<Emits>()

const inputId = ref(`input-${Math.random().toString(36).substr(2, 9)}`)
const touched = ref(false)
const focused = ref(false)
const errorMessage = ref('')

const inputValue = computed({
  get: () => props.modelValue || '',
  set: (value: string | number) => {
    emit('update:modelValue', value)
  }
})

const hasError = computed(() => !!errorMessage.value)

const isValid = computed(() => {
  if (!props.rules || props.rules.length === 0) return true
  return !hasError.value && touched.value
})

const inputClass = computed(() => {
  const baseClass = 'block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500'
  const sizeClass = {
    small: 'px-3 py-1.5 text-sm',
    medium: 'px-3 py-2 text-sm',
    large: 'px-4 py-3 text-base'
  }[props.size]
  
  const stateClass = hasError.value
    ? 'border-red-300 text-red-900 placeholder-red-300 focus:border-red-500 focus:ring-red-500'
    : isValid.value && touched.value
    ? 'border-green-300 focus:border-green-500 focus:ring-green-500'
    : 'border-gray-300 focus:border-blue-500 focus:ring-blue-500'
  
  const disabledClass = props.disabled ? 'bg-gray-50 text-gray-500 cursor-not-allowed' : ''
  const readonlyClass = props.readonly ? 'bg-gray-50' : ''
  
  return [baseClass, sizeClass, stateClass, disabledClass, readonlyClass].filter(Boolean).join(' ')
})

const validate = () => {
  if (!props.rules || props.rules.length === 0) {
    errorMessage.value = ''
    emit('validate', true)
    return true
  }
  
  for (const rule of props.rules) {
    const result = rule(inputValue.value)
    if (result !== true) {
      errorMessage.value = typeof result === 'string' ? result : '输入无效'
      emit('validate', false, errorMessage.value)
      return false
    }
  }
  
  errorMessage.value = ''
  emit('validate', true)
  return true
}

const handleBlur = (event: FocusEvent) => {
  focused.value = false
  touched.value = true
  
  if (props.validateOnBlur) {
    nextTick(() => {
      validate()
    })
  }
  
  emit('blur', event)
}

const handleFocus = (event: FocusEvent) => {
  focused.value = true
  emit('focus', event)
}

const handleInput = (event: Event) => {
  if (props.validateOnInput && touched.value) {
    nextTick(() => {
      validate()
    })
  }
  
  emit('input', event)
}

// 监听外部值变化时重新验证
watch(() => props.modelValue, () => {
  if (touched.value && (props.validateOnInput || props.validateOnBlur)) {
    nextTick(() => {
      validate()
    })
  }
})

// 暴露验证方法给父组件
defineExpose({
  validate,
  focus: () => {
    const input = document.getElementById(inputId.value)
    if (input) {
      input.focus()
    }
  },
  blur: () => {
    const input = document.getElementById(inputId.value)
    if (input) {
      input.blur()
    }
  }
})
</script>

<style scoped>
.validated-input {
  @apply w-full;
}
</style>